package com.drug.lib.view.recycptr;

import android.view.LayoutInflater;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;

import com.drug.lib.view.recycptr.loadMore.LoadMore;

import java.util.Collections;
import java.util.List;


public class DynamicRecyclerAdapter<T> extends RecyclerView.Adapter<ViewHolder> {

    private @NonNull
    List<?> mItems;
    private @NonNull
    AdapterTypePool mTypePool;

    private OnItemClickListener onItemClickListener;

    public DynamicRecyclerAdapter() {
        this(Collections.emptyList());
    }

    public DynamicRecyclerAdapter(@NonNull List<?> items) {
        this(items, new DynamicAdpTypePool());
    }

    public DynamicRecyclerAdapter(@NonNull List<?> items, @NonNull DynamicAdpTypePool dynamicAdpTypePool) {
        this.mItems = items;
        this.mTypePool = dynamicAdpTypePool;
    }

    @Override
    public void onViewAttachedToWindow(@NonNull ViewHolder holder) {
        getRealItemViewHolder(holder).onViewAttachedToWindow(holder);
    }

    @Override
    public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
        getRealItemViewHolder(holder).onViewDetachedFromWindow(holder);
    }

    private @NonNull
    ItemViewBinder getRealItemViewHolder(@NonNull ViewHolder holder) {
        return mTypePool.getItemViewBinder(holder.getItemViewType());
    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }

    @Override
    @SuppressWarnings("unchecked")
    public final long getItemId(int position) {
        Object item = mItems.get(position);
        int itemViewType = getItemViewType(position);
        ItemViewBinder binder = mTypePool.getItemViewBinder(itemViewType);
        return binder.getItemId(item);
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
            GridLayoutManager gridLayoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    if (mItems != null && mItems.get(position) instanceof LoadMore && position == getItemCount() - 1) {
                        return gridLayoutManager.getSpanCount();
                    } else {
                        return 1;
                    }
                }
            });
        }
    }

    @Override
    public int getItemViewType(int position) {
        Object o = mItems.get(position);
        return indexInTypesOf(position, o);
    }

    int indexInTypesOf(int position, @NonNull Object item) throws BinderNotFoundException {
        int index = mTypePool.firstIndexOf(item.getClass());
        if (index != -1) {
            Linker<?> linker1 =
                    mTypePool.getLinker(index);
            Linker<Object> linker = (Linker<Object>) linker1;
            return index + linker.index(position, item);
        }
        throw new BinderNotFoundException(item.getClass());
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        onBindViewHolder(holder, position, Collections.emptyList());
    }


    @Override
    @SuppressWarnings("unchecked")
    public final void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
        Object item = mItems.get(position);
        ItemViewBinder binder = mTypePool.getItemViewBinder(holder.getItemViewType());
        binder.onBindViewHolder(holder, item, payloads);
    }

    @Override
    public final ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        ItemViewBinder<?, ?> binder = mTypePool.getItemViewBinder(viewType);
        ViewHolder viewHolder = binder.onCreateViewHolder(inflater, parent);
        viewHolder.itemView.setOnClickListener(v -> {
            if (onItemClickListener != null)
                onItemClickListener.onItemClick(this, viewHolder.itemView, viewHolder.getLayoutPosition());
        });

        return viewHolder;
    }

    public void registerAll(@NonNull final AdapterTypePool pool) {
        final int size = pool.size();
        for (int i = 0; i < size; i++) {
            registerWithoutChecking(pool.getClass(i), pool.getItemViewBinder(i), pool.getLinker(i));
        }
    }

    private void registerWithoutChecking(@NonNull Class clazz, @NonNull ItemViewBinder binder, @NonNull Linker linker) {
        register(clazz, binder, linker);
    }

    public <T> void register(@NonNull Class<? extends T> clazz, @NonNull ItemViewBinder<T, ?> binder) {
        register(clazz, binder, new DefaultLinker<T>());
    }

    <T> void register(@NonNull Class<? extends T> clazz, @NonNull ItemViewBinder<T, ?> binder, @NonNull Linker<T> linker) {
        mTypePool.register(clazz, binder, linker);
        binder.mAdapter = this;
    }

    public void setItems(@NonNull List<?> items) {
        this.mItems = items;
    }


    public @NonNull
    List<?> getItems() {
        return mItems;
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }
}
